

local bit = require("bit")
local tobit, tohex, bnot = bit.tobit or bit.cast, bit.tohex, bit.bnot
local bor, band, bxor = bit.bor, bit.band, bit.bxor
local lshift, rshift, rol, bswap = bit.lshift, bit.rshift, bit.rol, bit.bswap
local byte, char, sub, rep = string.byte, string.char, string.sub, string.rep

local function tr_f(a, b, c, d, x, s)
	return rol(bxor(d, band(b, bxor(c, d))) + a + x, s) + b
  end
  
  local function tr_g(a, b, c, d, x, s)
	return rol(bxor(c, band(d, bxor(b, c))) + a + x, s) + b
  end
  
  local function tr_h(a, b, c, d, x, s)
	return rol(bxor(b, c, d) + a + x, s) + b
  end
  
  local function tr_i(a, b, c, d, x, s)
	return rol(bxor(c, bor(b, bnot(d))) + a + x, s) + b
  end
  
  local function transform(x, a1, b1, c1, d1)
	local a, b, c, d = a1, b1, c1, d1
  
	a = tr_f(a, b, c, d, x[ 1] + 0xd76aa478,  7)
	d = tr_f(d, a, b, c, x[ 2] + 0xe8c7b756, 12)
	c = tr_f(c, d, a, b, x[ 3] + 0x242070db, 17)
	b = tr_f(b, c, d, a, x[ 4] + 0xc1bdceee, 22)
	a = tr_f(a, b, c, d, x[ 5] + 0xf57c0faf,  7)
	d = tr_f(d, a, b, c, x[ 6] + 0x4787c62a, 12)
	c = tr_f(c, d, a, b, x[ 7] + 0xa8304613, 17)
	b = tr_f(b, c, d, a, x[ 8] + 0xfd469501, 22)
	a = tr_f(a, b, c, d, x[ 9] + 0x698098d8,  7)
	d = tr_f(d, a, b, c, x[10] + 0x8b44f7af, 12)
	c = tr_f(c, d, a, b, x[11] + 0xffff5bb1, 17)
	b = tr_f(b, c, d, a, x[12] + 0x895cd7be, 22)
	a = tr_f(a, b, c, d, x[13] + 0x6b901122,  7)
	d = tr_f(d, a, b, c, x[14] + 0xfd987193, 12)
	c = tr_f(c, d, a, b, x[15] + 0xa679438e, 17)
	b = tr_f(b, c, d, a, x[16] + 0x49b40821, 22)
  
	a = tr_g(a, b, c, d, x[ 2] + 0xf61e2562,  5)
	d = tr_g(d, a, b, c, x[ 7] + 0xc040b340,  9)
	c = tr_g(c, d, a, b, x[12] + 0x265e5a51, 14)
	b = tr_g(b, c, d, a, x[ 1] + 0xe9b6c7aa, 20)
	a = tr_g(a, b, c, d, x[ 6] + 0xd62f105d,  5)
	d = tr_g(d, a, b, c, x[11] + 0x02441453,  9)
	c = tr_g(c, d, a, b, x[16] + 0xd8a1e681, 14)
	b = tr_g(b, c, d, a, x[ 5] + 0xe7d3fbc8, 20)
	a = tr_g(a, b, c, d, x[10] + 0x21e1cde6,  5)
	d = tr_g(d, a, b, c, x[15] + 0xc33707d6,  9)
	c = tr_g(c, d, a, b, x[ 4] + 0xf4d50d87, 14)
	b = tr_g(b, c, d, a, x[ 9] + 0x455a14ed, 20)
	a = tr_g(a, b, c, d, x[14] + 0xa9e3e905,  5)
	d = tr_g(d, a, b, c, x[ 3] + 0xfcefa3f8,  9)
	c = tr_g(c, d, a, b, x[ 8] + 0x676f02d9, 14)
	b = tr_g(b, c, d, a, x[13] + 0x8d2a4c8a, 20)
  
	a = tr_h(a, b, c, d, x[ 6] + 0xfffa3942,  4)
	d = tr_h(d, a, b, c, x[ 9] + 0x8771f681, 11)
	c = tr_h(c, d, a, b, x[12] + 0x6d9d6122, 16)
	b = tr_h(b, c, d, a, x[15] + 0xfde5380c, 23)
	a = tr_h(a, b, c, d, x[ 2] + 0xa4beea44,  4)
	d = tr_h(d, a, b, c, x[ 5] + 0x4bdecfa9, 11)
	c = tr_h(c, d, a, b, x[ 8] + 0xf6bb4b60, 16)
	b = tr_h(b, c, d, a, x[11] + 0xbebfbc70, 23)
	a = tr_h(a, b, c, d, x[14] + 0x289b7ec6,  4)
	d = tr_h(d, a, b, c, x[ 1] + 0xeaa127fa, 11)
	c = tr_h(c, d, a, b, x[ 4] + 0xd4ef3085, 16)
	b = tr_h(b, c, d, a, x[ 7] + 0x04881d05, 23)
	a = tr_h(a, b, c, d, x[10] + 0xd9d4d039,  4)
	d = tr_h(d, a, b, c, x[13] + 0xe6db99e5, 11)
	c = tr_h(c, d, a, b, x[16] + 0x1fa27cf8, 16)
	b = tr_h(b, c, d, a, x[ 3] + 0xc4ac5665, 23)
  
	a = tr_i(a, b, c, d, x[ 1] + 0xf4292244,  6)
	d = tr_i(d, a, b, c, x[ 8] + 0x432aff97, 10)
	c = tr_i(c, d, a, b, x[15] + 0xab9423a7, 15)
	b = tr_i(b, c, d, a, x[ 6] + 0xfc93a039, 21)
	a = tr_i(a, b, c, d, x[13] + 0x655b59c3,  6)
	d = tr_i(d, a, b, c, x[ 4] + 0x8f0ccc92, 10)
	c = tr_i(c, d, a, b, x[11] + 0xffeff47d, 15)
	b = tr_i(b, c, d, a, x[ 2] + 0x85845dd1, 21)
	a = tr_i(a, b, c, d, x[ 9] + 0x6fa87e4f,  6)
	d = tr_i(d, a, b, c, x[16] + 0xfe2ce6e0, 10)
	c = tr_i(c, d, a, b, x[ 7] + 0xa3014314, 15)
	b = tr_i(b, c, d, a, x[14] + 0x4e0811a1, 21)
	a = tr_i(a, b, c, d, x[ 5] + 0xf7537e82,  6)
	d = tr_i(d, a, b, c, x[12] + 0xbd3af235, 10)
	c = tr_i(c, d, a, b, x[ 3] + 0x2ad7d2bb, 15)
	b = tr_i(b, c, d, a, x[10] + 0xeb86d391, 21)
  
	return tobit(a+a1), tobit(b+b1), tobit(c+c1), tobit(d+d1)
  end
  

function md5(msg)
	local len = #msg
	msg = msg.."\128"..rep("\0", 63 - band(len + 8, 63))
		 ..char(band(lshift(len, 3), 255), band(rshift(len, 5), 255),
			band(rshift(len, 13), 255), band(rshift(len, 21), 255))
		 .."\0\0\0\0"
	local a, b, c, d = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
	local x, k = {}, 1
	for i=1,#msg,4 do
	  local m0, m1, m2, m3 = byte(msg, i, i+3)
	  x[k] = bor(m0, lshift(m1, 8), lshift(m2, 16), lshift(m3, 24))
	  if k == 16 then
		a, b, c, d = transform(x, a, b, c, d)
		k = 1
	  else
		k = k + 1
	  end
	end
	return tohex(bswap(a))..tohex(bswap(b))..tohex(bswap(c))..tohex(bswap(d))
end

--查找对象--
function find(str)
	return GameObject.Find(str);
end

function destroy(obj, delay)
	if delay then
		GameObject.Destroy(obj, delay);
	else
		GameObject.Destroy(obj);
	end
end

function destroyImmediate(obj)
	GameObject.DestroyImmediate(obj);
end

local macAddress = ""
function GetMacAddress()
	if macAddress ~= "" then
		return macAddress
	end
	local interfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
	for i = 0, interfaces.Length - 1 do
		interface = interfaces[i]
		if interface.Description == "en0" then
			macAddress = interface:GetPhysicalAddress():ToString()
			break
		else
			macAddress = interface:GetPhysicalAddress():ToString()
			if macAddress ~= "" then
				break
			end
		end
	end
	macAddress = string.upper(macAddress)
	return macAddress
end

function newObject(prefab)
	return GameObject.Instantiate(prefab);
end

--创建面板--
function createPanel(name)
	PanelManager:CreatePanel(name);
end

function child(str)
	return transform:Find(str);
end

function subGet(childNode, typeName)		
	return child(childNode):GetComponent(typeName);
end

function findPanel(str) 
	local obj = find(str);
	if obj == nil then
		error(str.." is null");
		return nil;
	end
	return obj:GetComponent("BaseLua");
end

function stringToVector3(str)
	if str and string.len(str)~=0 then 
		local pos = {}
		local txt = string.gsub(string.gsub(str, "%[", ""), "%]", "")
		pos = string.split(txt, ",")
		-- string.gsub(txt, "(%s),(%s),(%s)", function(x, y, z)
		-- 	pos["x"] = x
		-- 	pos["y"] = y
		-- 	pos["z"] = z
		-- end)
		if pos[1] and pos[2] and pos[3] then 
			return Vector3.New(tonumber(pos[1]), tonumber(pos[2]), tonumber(pos[3]))
		else 
			return nil
		end
	else 
		return nil
	end
end
function string.split(str, delimiter)
	if str==nil or str=='' or delimiter==nil then
		return nil
	end
	
    local result = {}
    for match in (str..delimiter):gmatch("(.-)"..delimiter) do
        table.insert(result, match)
    end
    return result
end

-- function GetField(obj, fieldName)
-- 	if not obj then
-- 		return nil
-- 	end

-- 	if type(obj) == "userdata" then
-- 		if obj:GetType() == typeof(FieldDictionary) then
-- 			return obj:Get(fieldName)
-- 		elseif typeof(ISerializableFieldContainer):IsAssignableFrom(obj:GetType()) then
-- 			return ISerializableFieldContainer.GetFieldDictionary(obj):Get(fieldName)
-- 		end
-- 	end
-- 	return obj[fieldName]
-- end

-- function GetTypeName(obj)
-- 	if not obj then
-- 		return
-- 	end

-- 	local fieldDictionary = nil
-- 	if type(obj) == "userdata" then
-- 		if not typeof(ISerializableFieldContainer):IsAssignableFrom(obj:GetType()) then
-- 			return obj:GetType().FullName
-- 		else
-- 			fieldDictionary = ISerializableFieldContainer.GetFieldDictionary(obj)
-- 		end
-- 	elseif type(obj) == "table" then
-- 		fieldDictionary = obj._fieldDictionary
-- 	end

-- 	if fieldDictionary then
-- 		return fieldDictionary.className
-- 	end
-- end

-- function InstantiateNew(obj)
-- 	if not obj then
-- 		return
-- 	end

-- 	if type(obj) == "table" then
-- 		local v = newObject(obj._dataContainer)
-- 		return CreateDataContainerProxy(v)
-- 	end

-- 	return newObject(obj)
-- end

-- function GetComponentNew(obj, classType)
-- 	if not obj then
-- 		return
-- 	end

-- 	if type(obj) == "table" then
-- 		obj = obj._dataContainer
-- 	end

-- 	if not obj or obj:Equals(nil) then
-- 		return
-- 	end

-- 	local v = obj:GetComponent(typeof(SerializeEx.ISerializableFieldContainer))
-- 	if v ~= nil then
-- 		if type(classType) == "string" then
-- 			local fieldDictionary = ISerializableFieldContainer.GetFieldDictionary(v)
-- 			if fieldDictionary.className ~= classType then
-- 				local vs = v:GetComponentsEx(typeof(ISerializableFieldContainer))
-- 				for i = 0, vs.Count - 1 do
-- 					local v2 = vs[i]
-- 					fieldDictionary = ISerializableFieldContainer.GetFieldDictionary(v2)
-- 					if fieldDictionary.className == classType then
-- 						v = v2
-- 						break
-- 					end
-- 				end
-- 				UnityListPools.Recycle(vs)
-- 			end
-- 		end
		
-- 		v = CreateDataContainerProxy(v)
-- 		return v
-- 	end
	
-- 	if classType ~= nil then
-- 		return obj:GetComponent(typeof(classType))
-- 	end
-- end


-- local DataContainerProxy = {}



-- function DataContainerProxy.__index(t, k)
-- 	local v, hasKey = t._fieldDictionary:Get(k, nil)
-- 	if type(v) == "userdata" then
-- 		if v:GetType() == typeof(SerializeEx.FieldDictionary) then
-- 			v = CreateDataContainerProxy(v)
-- 		elseif typeof(SerializeEx.ISerializableFieldContainer):IsAssignableFrom(v:GetType()) then
-- 			v = CreateDataContainerProxy(v)
-- 		end

-- 		if v ~= nil then
-- 			rawset(t, k, v)
-- 			return v
-- 		end
-- 	end

-- 	if v == nil and not hasKey then
-- 		v = DataContainerProxy[k]
-- 		if not v then
-- 			local dataContainer = rawget(t, "_dataContainer")
-- 			if dataContainer and not dataContainer:Equals(nil) then
-- 				return dataContainer[k]
-- 			end
-- 		end
-- 	end

-- 	return v
-- end

-- function DataContainerProxy.__newindex(t, k, v)
-- 	rawset(t, k, v)
	
-- 	-- t._fieldDictionary:Set(k, v)
-- end

-- -- function DataContainerProxy.__eq(a, b)
-- -- 	if rawequal(a, b) then
-- -- 		return true
-- -- 	elseif a._dataContainer == b then
-- -- 		return true
-- -- 	elseif a._fieldDictionary == b then
-- -- 		return true
-- -- 	end

-- -- 	return false
-- -- end

-- function DataContainerProxy:GetComponent(t)
-- 	return self.gameObject:GetComponent(t)
-- end

-- function DataContainerProxy:GetComponentInChildren(t, includeInactive)
-- 	return self.gameObject:GetComponentInChildren(t, includeInactive)
-- end

-- function DataContainerProxy:GetComponentInParent(t)
-- 	return self.gameObject:GetComponentInParent(t)
-- end

-- function DataContainerProxy:GetComponents(t, result)
-- 	return self.gameObject:GetComponents(t, result)
-- end

-- function DataContainerProxy:GetComponentsInChildren(t, includeInactive)
-- 	return self.gameObject:GetComponentsInChildren(t, includeInactive)
-- end

-- function DataContainerProxy:GetComponentsInParent(t, includeInactive)
-- 	return self.gameObject:GetComponentsInParent(t, includeInactive)
-- end

-- function DataContainerProxy:Equals(v)
-- 	if not self then
-- 		return self == v
-- 	end
	
-- 	local obj = self.gameObject

-- 	if not obj then
-- 		return obj == v
-- 	end
	
-- 	return obj:Equals(v)
-- end


-- local fieldDictionaryTableMap = {}
-- setmetatable(fieldDictionaryTableMap, {__mode='kv'})


-- function CreateDataContainerProxy(obj)
-- 	if not obj then
-- 		return obj
-- 	end

-- 	local fieldDictionary = nil
-- 	local dataContainer = nil
-- 	if type(obj) == "userdata" then
-- 		if obj:GetType() == typeof(SerializeEx.FieldDictionary) then
-- 			fieldDictionary = obj
-- 		elseif typeof(SerializeEx.ISerializableFieldContainer):IsAssignableFrom(obj:GetType()) then
-- 			dataContainer = obj
-- 			fieldDictionary = SerializeEx.ISerializableFieldContainer.GetFieldDictionary(obj)
-- 		else
-- 			return obj
-- 		end
-- 	else
-- 		return obj
-- 	end

-- 	local mode = 2
-- 	if mode == 1 then
-- 		if fieldDictionary.userData then
-- 			return fieldDictionary.userData
-- 		end
-- 	elseif mode == 2 then
-- 		if fieldDictionaryTableMap[fieldDictionary] then
-- 			return fieldDictionaryTableMap[fieldDictionary]
-- 		end
-- 	end

-- 	local me = fieldDictionary.this
-- 	if not me._fieldDictionary then
-- 		me._fieldDictionary = fieldDictionary
-- 		me._dataContainer = dataContainer
-- 		setmetatable(me, DataContainerProxy)
-- 		if mode == 1 then
-- 			fieldDictionary.userData = me
-- 		end

-- 		if mode == 2 then
-- 			fieldDictionaryTableMap[fieldDictionary] = me
-- 		end
-- 	end
-- 	return me
-- end

-- function CreateBehaviourProxy(ctrlName, dataObj, funObj)
-- 	local ctrl = _G[ctrlName]
-- 	local me = {_ctrl = ctrl, _dataObj = dataObj, _funObj = funObj}
-- 	me = New(ctrl, me)
-- 	return me
-- end

function GetClassFun(self, funName)
	return self[funName]
end

-- function NewClass(baseClass, newClass)
-- 	newClass = newClass or {};
-- 	newClass.super = baseClass;
--  	setmetatable(newClass, baseClass);
--  	baseClass.__index = baseClass;
--  	return newClass;
-- end

-- function New(class, me)
-- 	me = me or {};
--  	setmetatable(me, class);
--  	class.__index = class;

--  	if me._init then
--  		me:_init()
--  	end
--  	return me;
-- end

function CreateCallBack(fun, self)
	local f = function(...)
		return fun(self, ...)
	end
	return f
end

function ReverseTable(table)
	local ret = {}
	for k,v in pairs(table) do
		ret[v] = k
	end
	return ret
end

function KeyKeyTable(table)
	local ret = {}
	for k,v in pairs(table) do
		ret[k] = k
	end
	return ret
end

function KeyArray(table)
	local ret = {}
	for k,v in pairs(table) do
		ret[#ret + 1] = k
	end
	return ret
end

function ValueArray(table)
	local ret = {}
	for k,v in pairs(table) do
		ret[#ret + 1] = v
	end
	return ret
end

function PrintTable(t)
	if not t then
		logError("table is nil")
		return
	end
	local logStr = "len:"..#t.." \n"
	for k,v in pairs(t) do
		local vStr =  tostring(v)
		if not vStr then
			vStr = "type("..type(v)..")"
		end

		logStr = logStr.."("..tostring(k)..","..vStr..") \n"
	end
	logError(logStr)
end


MathUtil = {}

-- return: new v3
function MathUtil.DegToVec3(deg)
	local rad = math.rad(deg)
	local z = math.cos(rad)
	local x = math.sin(rad)
	local dir = Vector3Ex.New(x, 0, z)
	return dir
end

function MathUtil.DegToVec3NoAlloc(dir, deg)
	local rad = math.rad(deg)
	local z = math.cos(rad)
	local x = math.sin(rad)
	dir:Set(x, 0, z)
end

function table.clear(t)
	if type(t) ~= "table" then
		return
	end

	local keys = {}
	for k,v in pairs(t) do
		table.insert(keys, k)
	end

	for k,v in pairs(keys) do
		t[v] = nil
	end
end

function table.find(t, fun)
	if not t then
		return
	end
	
	for k,v in pairs(t) do
		if fun(k, v) then
			return k,v
		end
	end
end

function table.len(t)
	local len = 0
	if t then
		for k,v in pairs(t) do
			len = len + 1
		end
	end
	return len
end

function table.first(t)
	for k,v in pairs(t) do
		return v
	end
end

function table.removeByValue(t, value)
	if not t then
		return
	end
	
	for k,v in pairs(t) do
		if v == value then
			table.remove(t, k)
			return
		end
	end
end

-- function GetLayerMask(layerName)
-- 	local layerMask = bit.lshift(1, UnityEngine.LayerMask.NameToLayer(layerName))
-- 	return layerMask
-- end

function IsClassOrSubclassOf(t0, t1)
	return t0 == t1 or t0:IsSubclassOf(t1)
end

function keyCompare(a, b)
	local ta = type(a)
	local tb = type(b)
	if ta == tb then
		if ta == "function" or tb == "function" then
			return tostring(a) < tostring(b)
		end

		if ta == "table" or tb == "table" then
			return tostring(a) < tostring(b)
		end

		return a < b
	end

	return ta < tb
end

function GetTableMinDepthNameMap(obj, depth, tableNameMap, tableDepthMap, tableNameStack)
	local t = type(obj)
    if t == "table" then
    	if not tableNameMap then
    		tableNameMap = {}
    	end

    	if not tableDepthMap then
    		tableDepthMap = {}
    	end

    	if not tableNameStack then
    		tableNameStack = {}
    	end

    	depth = depth or 0

    	local oldDepth = tableDepthMap[obj]
    	if oldDepth then
    		if depth >= oldDepth then
    			return
    		end
    	end
    	tableDepthMap[obj] = depth

    	tableName = ""
		for k,v in ipairs(tableNameStack) do
			tableName = tableName.."."..tostring(v)
		end
		tableNameMap[obj] = tableName

    	for k,v in pairs(obj) do
			if type(v) == "table" then
	        	table.insert(tableNameStack, k)
	        	GetTableMinDepthNameMap(v, depth + 1, tableNameMap, tableDepthMap, tableNameStack)
	        	table.remove(tableNameStack)
	        end
    	end
    end
    return tableNameMap
end

function serialize(obj, prefix, tableSet, tableNameStack, tableNameMap)
	local prefix = prefix or ""
	local valuePrefix = prefix.."\t"
    local lua = ""  
    local t = type(obj)  
    if t == "number" then  
        lua = lua .. obj  
    elseif t == "boolean" then  
        lua = lua .. tostring(obj)  
    elseif t == "string" then  
        lua = lua .. string.format("%q", obj)  
    elseif t == "table" then
    	if not tableSet then
    		tableSet = {}
    	end

    	local tableName = tableSet[obj]
    	if tableName ~= nil then
    		tostring("test: "..tostring(tableName))
			lua = lua..serialize("repeated("..tableName..")", prefix)
    	else
    		if not tableNameStack then
	    		tableNameStack = {}
	    	end

    		tableName = ""
    		for k,v in ipairs(tableNameStack) do
    			tableName = tableName.."."..tostring(v)
    		end

    		local needSerialize = true
    		if tableNameMap then
    			local minDepthName = tableNameMap[obj]
    			if minDepthName and minDepthName ~= tableName then
    				-- logError("test repeat: "..tableName.."  "..type(obj))
    				needSerialize = false
    				lua = lua..serialize("repeated("..tableName.." "..tostring(obj)..")", prefix)		
    			end
    		end

    		if needSerialize then


	    		tableSet[obj] = tableName.." "..tostring(obj)


		        lua = lua.."\n"..prefix.."{\n"  
		        local newPrefix = prefix.."\t"

		        local keys = KeyArray(obj)
		        table.sort(keys, keyCompare)
		        for i = 1, #keys do
		        	local k = keys[i]
		        	local v = obj[keys[i]]

		        	if type(v) == "table" then
			        	table.insert(tableNameStack, k)
			        end
		        	lua = lua..valuePrefix.."[" ..serialize(k, nil, tableSet, tableNameStack, tableNameMap) .. "]=" ..serialize(v, newPrefix, tableSet, tableNameStack, tableNameMap).. ",\n"  
		        	if type(v) == "table" then
			        	table.remove(tableNameStack)
			        end
		        end

			    local metatable = getmetatable(obj)  
			        if metatable ~= nil and type(metatable.__index) == "table" then  
			        for k, v in pairs(metatable.__index) do
			        	if type(v) == "table" then
				        	table.insert(tableNameStack, k)
				        end

			            lua = lua ..valuePrefix.."[" .. serialize(k, nil, tableSet, tableNameStack, tableNameMap) .. "]=" .. serialize(v, newPrefix, tableSet, tableNameStack, tableNameMap) .. ",\n"  
	    	        	if type(v) == "table" then
				        	table.remove(tableNameStack)
				        end
			        end
			    end  
		        lua = lua ..prefix.. "}"
		    end
    	end
    elseif t == "nil" then  
        return nil  
    else
        return "\""..tostring(obj).."("..t..")".."\""
    end
    return lua
end

function convertToEditable(obj)
	local t = type(obj)  
	if t == "number" then
		return tostring(obj)
	elseif t == "table" then  
		for k,v in pairs(obj) do
			obj[k] = convertToEditable(v)
		end
	end
	return obj
end

function convertToNotEditable(obj)
	local t = type(obj)  
	if t == "string" then  
		local num = tonumber(obj)
		if num then
			return num
		end
	elseif t == "table" then  
		for k,v in pairs(obj) do
			obj[k] = convertToNotEditable(v)
		end
	end
	return obj
end

function unserialize(str)
	return loadstring("return "..str)();
end

local EPSILON = 0.000001  
function Vector3.SignedAngle(a, b)
	local angle = a:Angle(b)
	-- logError(Concat(nil, "test1: ", angle))

	local c = a:Cross(b)
	-- logError(Concat(nil, "test2: ", c))

	if math.abs(c.z) < EPSILON then
		if math.abs(c.y) < EPSILON then
			if math.abs(c.x) < EPSILON then
				return 0
			else
				if c.x < 0 then
					angle = -angle
				end
			end
		else
			if c.y < 0 then
				angle = -angle
			end
		end
	else
		if c.z < 0 then
			angle = -angle
		end
	end
	
	-- if c.x < 0 or c.y < 0 or c.z < 0 then
	-- 	angle = -angle
	-- end
	return angle
end

function Vector2.SignedAngle(a, b)
	local angle = a:Angle(b)

	local c = a.x * b.y - a.y * b.x

	if math.abs(c) < EPSILON then
		return 0;
	else
		if c < 0 then
			angle = -angle
		end
	end
	
	-- if c.x < 0 or c.y < 0 or c.z < 0 then
	-- 	angle = -angle
	-- end
	return angle
end



function GenPlayerUUID(serverId, dbid)
	return tostring(serverId).."_"..tostring(dbid)
end

function GetPlayerServerIdDBID(serverDBID)
	return string.split(serverDBID, "_")
end

--q权限转十进制
function convertPremissionToNumber(premission)
	local sum = 0
	local n = 1
	for i, k in ipairs(premission) do
		if premission[i] == true then
			sum = sum + 2^(n-1)
		end
		n = n + 1
	end
	return sum
end

--获取权限
function GetPermissionSelf(premissionSum) 
	local sum = premissionSum
	--权限位运算
	-- for i=1,4 do
	-- 	logError("tobit"..i..":::".. bit.band(bit.arshift(sum,i-1),1))
	-- end
	local premission = {
		[GuildPermission.proclaimWar] = false, --宣战  1最左 g
		[GuildPermission.upgrade] = false,     --升级公会建筑 2
		[GuildPermission.apply] = false,		 --申请审批 3
		[GuildPermission.kickOut] = false,	 --踢出成员 4
	}
	local n = 1
	for i, k in ipairs(premission) do
		if bit.band(bit.arshift(sum,n-1),1) == 1 then 
			premission[i] = true
		elseif bit.band(bit.arshift(sum,n-1),1) == 0 then
			premission[i] = false
		end
		n = n + 1
	end
	return premission
end

-- 获取签到状态
function GetSignState(arg)
	local state = {}
	local n = 1
	for i=1,30 do
		if bit.band(bit.arshift(arg,n-1),1) == 1 then 
			state[i] = true
		elseif bit.band(bit.arshift(arg,n-1),1) == 0 then
			state[i] = false
		end
		n = n + 1
	end
	return state
end

--获取二进制状态
function GetBitState(index, arg)
	local state = {}
	local n = 1
	for i=1,index do
		if bit.band(bit.arshift(arg,n-1),1) == 1 then 
			state[i] = true
		elseif bit.band(bit.arshift(arg,n-1),1) == 0 then
			state[i] = false
		end
		n = n + 1
	end
	return state
end

--获取时间戳 年月日
function GetTime(curTime)
	local str = os.date("%Y-%m-%d",curTime)
	local time = {}
	string.gsub(str, "(%d+)-(%d+)-(%d+)", function(year, month, day)
		time["year"] = year
		time["month"] = month
		time["day"] = day
	end)
	return time
end
--获取时间戳 时分秒
function GetTimeHMS(curTime)
	local str = os.date("%H:%M:%S",curTime)
	local time = {}
	string.gsub(str, "(%d+):(%d+):(%d+)", function(hour, minute, second)
		time["hour"] = tonumber(hour)
		time["minute"] = tonumber(minute)
		time["second"] = tonumber(second)
	end)
	return time
end
--生成时间凌晨时间戳
function GetEarlyMorningTime(time)
	if time == 0 then
		return time
	end
	local str = os.date("%Y-%m-%d", time)
	local earlyMorningTime = {hour=0, min=0, sec=0}
	string.gsub(str, "(%d+)-(%d+)-(%d+)", function(year, month, day)
		earlyMorningTime["year"] = year
		earlyMorningTime["month"] = month
		earlyMorningTime["day"] = day
	end)
	return os.time(earlyMorningTime)
end

--table log 辅助函数
local function dump_value_(v)
    if type(v) == "string" then
        v = "\"" .. v .. "\""
    end
    return tostring(v)
end
--打印table
function dump(value, desciption, nesting)
	-- if type(nesting) ~= "number" then nesting = 3 end

	-- local lookupTable = {}
	-- local result = {}
	-- --local traceback = string.split(debug.traceback("", 2), "\n")
	-- --print("dump from: " .. string.trim(traceback[3]))

	-- local function dump_(value, desciption, indent, nest, keylen)
	-- 	desciption = desciption or "<var>"
	-- 	local spc = ""
	-- 	if type(keylen) == "number" then
	-- 		spc = string.rep(" ", keylen - string.len(dump_value_(desciption)))
	-- 	end
	-- 	if type(value) ~= "table" then
	-- 		result[#result +1 ] = string.format("%s%s%s = %s", indent, dump_value_(desciption), spc, dump_value_(value))
	-- 	elseif lookupTable[tostring(value)] then
	-- 		result[#result +1 ] = string.format("%s%s%s = *REF*", indent, dump_value_(desciption), spc)
	-- 	else
	-- 		lookupTable[tostring(value)] = true
	-- 		if nest > nesting then
	-- 			result[#result +1 ] = string.format("%s%s = *MAX NESTING*", indent, dump_value_(desciption))
	-- 		else
	-- 			result[#result +1 ] = string.format("%s%s = {", indent, dump_value_(desciption))
	-- 			local indent2 = indent.."    "
	-- 			local keys = {}
	-- 			local keylen = 0
	-- 			local values = {}
	-- 			for k, v in pairs(value) do
	-- 				keys[#keys + 1] = k
	-- 				local vk = dump_value_(k)
	-- 				local vkl = string.len(vk)
	-- 				if vkl > keylen then keylen = vkl end
	-- 				values[k] = v
	-- 			end
	-- 			table.sort(keys, function(a, b)
	-- 				if type(a) == "number" and type(b) == "number" then
	-- 					return a < b
	-- 				else
	-- 					return tostring(a) < tostring(b)
	-- 				end
	-- 			end)
	-- 			for i, k in ipairs(keys) do
	-- 				dump_(values[k], k, indent2, nest + 1, keylen)
	-- 			end
	-- 			result[#result +1] = string.format("%s}", indent)
	-- 		end
	-- 	end
	-- end
	-- dump_(value, desciption, "- ", 1)

	-- logError(desciption..(serialize(result)))
	-- for i, line in ipairs(result) do
	--     print(line)
	-- end
	logError(desciption..tostring(serialize(value)))
end



function Concat(splitStr, ...)
	local log = ""
	local args = { ... }
	for i = 1, #args do
		log = log..tostring(args[i])
		if splitStr ~= nil and string.len(splitStr) > 0 and i ~= #args then
			log = log..tostring(splitStr)
		end
	end
	return log
end

function PrintTable(t, logStr, logFun, tableMinDepthName)
	if not logFun then
		logFun = log
	end

	if logStr then
		logFun(tostring(logStr)..tostring(serialize(t, nil, nil,  nil, tableMinDepthName)))
	else
		logFun(tostring(serialize(t, nil, nil,  nil, tableMinDepthName)))
	end
end

function GetMaskUint64(n, index)
	local low, high = uint64.tonum2(n)
	if index >= 32 then
		low = high
		index = index - 32
	end

	local mask = bit.lshift(1, index)
	-- logError("test:GetMaskUint64: "..tostring(n).."   "..tostring(index).."   "..tostring(low).."   "..tostring(mask).."  "..tostring(bit.band(low, mask)).."  "..tostring(bit.band(low, mask) ~= 0))
	return bit.band(low, mask) ~= 0
end

function SetMaskUint64(n, index)
	local low, high = uint64.tonum2(n)

	local useHigh = false
	local temp = low
	if index >= 32 then
		useHigh = true
		temp = high
		index = index - 32
	end

	local mask = bit.lshift(1, index)

	temp = bit.bor(temp, mask)

	if useHigh then
		high = temp
	else
		low = temp
	end

	return uint64.new(low, high)
end

